package jfae.core.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import jfae.core.configuration.contributions.Contribution;
import jfae.core.configuration.contributions.DuplicateContributionException;
import jfae.core.configuration.contributions.Overriding;
import jfae.core.properties.FieldInfo;
import jfae.core.properties.parsers.PropertyHandler;
import jfae.core.properties.parsers.annotation.AnnotationHandler;

public class InitializerWrapper{
	
	Method contribAnnMethod;
	Method overAnnMethod;
	Method contribPropMethod;
	Method overPropMethod;

	public InitializerWrapper(Class<?> type) {
		super();
		this.contribAnnMethod = getMethod(type, "contributeAnnotationsHandlers", Contribution.class);
		this.overAnnMethod = getMethod(type, "overrideAnnotationsHandlers", Overriding.class);
		this.contribPropMethod = getMethod(type, "contributePropertiesHandlers", Contribution.class);
		this.overPropMethod = getMethod(type, "overridePropertiesHandlers", Overriding.class);
	}
	
	public void contributeAnnotationsHandlers(Contribution<AnnotationHandler<?>> contributions){
		if(contribAnnMethod != null){
			invoke(contribAnnMethod, contributions);
		}
	}
	
	public void overrideAnnotationsHandlers(Overriding<AnnotationHandler<?>> contributions){
		if(overAnnMethod != null){
			invoke(overAnnMethod, contributions);
		}
	}
	
	public void contributePropertiesHandlers(Contribution<PropertyHandler<FieldInfo<?>>> contributions){
		if(contribPropMethod != null){
			invoke(contribPropMethod, contributions);
		}
	}
	
	public void overridePropertiesHandlers(Overriding<PropertyHandler<FieldInfo<?>>> contributions){
		if(overPropMethod != null){
			invoke(overPropMethod, contributions);
		}
	}
	
	Method getMethod(Class<?> type, String name, Class<?> ... params){
		try {
			return type.getMethod(name, params);
		} catch (Exception e) {
			// nothing to do
			return null;
		}
	}

	void invoke(Method method,
			Object ... params) {
		try {
			method.invoke(null, params);
		} catch (IllegalArgumentException e) {
			// TODO: marco loggare o addirittura lanciare una runtime exception
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO: marco loggare o addirittura lanciare una runtime exception
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			Throwable targetException = e.getTargetException();
			if (targetException instanceof DuplicateContributionException) {
				throw (DuplicateContributionException) targetException;
			}
			// TODO: marco loggare o addirittura lanciare una runtime exception
			e.printStackTrace();
		}
	}

}
